package Framework
{
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Common.b2Base;
	import Box2D.Common.b2Color;
	import Box2D.Dynamics.Joints.b2Joint;
	import Box2D.Dynamics.Joints.b2MouseJoint;
	import Box2D.Dynamics.Joints.b2MouseJointDef;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2ContactListener;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;
	
	import mx.collections.ArrayCollection;
	
	import org.osmf.layout.AbsoluteLayoutFacet;
	
	
	public class Test extends b2ContactListener
	{
		protected var m_world:b2World;
		protected var m_debugDraw:DebugDraw = new DebugDraw;
		protected var m_groundBody:b2Body;
		protected var m_destructionListener:DestructionListener
		public var m_mouseJoint:b2MouseJoint;
		protected var m_mouseWorld:b2Vec2;
		protected var m_stepCount:int
		
		private var _drawFlag:uint;
		[Bindable]
		public var messages:ArrayCollection = new ArrayCollection;
		[Bindable]
		public static var hertz:int = 30;
		[Bindable]
		public static var flag:uint = b2DebugDraw.e_shapeBit|b2DebugDraw.e_pairBit|b2DebugDraw.e_jointBit;
		[Bindable]
		public static var paused:Boolean;
		public static var steping:Boolean
		public function Test()
		{
			m_world = new b2World(new b2Vec2(0,-10),true);
			
			m_destructionListener = new DestructionListener(this);
			m_world.SetDestructionListener(m_destructionListener);
			m_world.SetContactListener(this);
			m_world.SetDebugDraw(m_debugDraw);
			
			
			var bodyDef:b2BodyDef = new b2BodyDef;
			m_groundBody = m_world.CreateBody(bodyDef);
			
		}
		public function get hotKeyNote():String{return ""}
		public function Delete():void{
			m_world.Delete();
			m_world = null;
		}
		[Bindable]
		public function get drawFlag():uint{return _drawFlag}
		public function set drawFlag(value:uint):void{
			_drawFlag = value;
			m_debugDraw.SetFlags(value);
			flag = value;
		}
		protected function writeMessage(msg:String):void{
			messages.addItem(msg);
		}
		public function get world():b2World{return m_world}
		public function get draw():b2DebugDraw{return m_debugDraw}
		private var _b2Container:Sprite = new Sprite;
		public function get b2Container():Sprite{return _b2Container}
		public function set container(value:Sprite):void{
			var minground:Sprite = new Sprite;
			_b2Container.addChild(minground)
			_b2Container.x = value.width/2;
			_b2Container.y = -value.height+50;//adjust with container's scaleY=-1
			value.addChild(_b2Container);
			
			m_debugDraw.sprite = minground
			m_debugDraw.drawScale = 12;
			m_debugDraw.fillAlpha = .2;
			drawFlag = flag;
			
		}
		public function get cameraX():Number{return -m_debugDraw.sprite.x/m_debugDraw.drawScale}
		public function set cameraX(value:Number):void{m_debugDraw.sprite.x=-value*m_debugDraw.drawScale}
		public function get viewZoom():Number{return _b2Container.scaleX}
		public function set viewZoom(value:Number):void{
			_b2Container.scaleX = _b2Container.scaleY = value;
		}
		public function ShiftMouseDown(p:b2Vec2):void{
			
		}
		public function MouseDown(p:b2Vec2):void{
			m_mouseWorld = p;
			if(m_mouseJoint)
				return;
			var aabb:b2AABB = new b2AABB;
			var d:b2Vec2 = new b2Vec2;
			d.Set(.001,.001);
			aabb.lowerBound = p.Subtract(d);
			aabb.upperBound = p.Add(d);
			var callback:QueryCallback = new QueryCallback(p);
			m_world.QueryAABB(callback,aabb);
			if(callback.m_fixture){
				var body:b2Body = callback.m_fixture.GetBody();
				var md:b2MouseJointDef = new b2MouseJointDef;
				md.bodyA = m_groundBody;
				md.bodyB = body;
				md.target = p;
				md.maxForce = 1000*body.GetMass();
				m_mouseJoint = m_world.CreateJoint(md) as b2MouseJoint;
				body.SetAwake(true);
			}
		}
		public function MouseMove(p:b2Vec2):void{
			m_mouseWorld = p;
			if(m_mouseJoint){
				m_mouseJoint.SetTarget(p);
			}
		}
		public function MouseUp(p:b2Vec2):void{
			if(m_mouseJoint){
				m_world.DestroyJoint(m_mouseJoint);
				m_mouseJoint = null;
			}			
		}
		public function Step():void{
			var timeStep:Number = 1.0/hertz;
			if(paused){
				if(steping){
					steping = false;	
				}				
				else{
					timeStep = 0;
				}
			}
			
			m_world.Step(timeStep,10,8);			
			m_world.ClearForces();
			m_world.DrawDebugData();
			
			if (timeStep > 0.0)
			{
				++m_stepCount;
			}

			if(m_mouseJoint){
				var p1:b2Vec2 = m_mouseJoint.GetAnchorB();
				var p2:b2Vec2 = m_mouseJoint.GetTarget();
				var c:b2Color = new b2Color;
				c.Set(0,1,0);
				m_debugDraw.DrawPoint(p1,1,c);
				m_debugDraw.DrawPoint(p2,1,c);
				c.Set(.8,.8,.8);
				m_debugDraw.DrawSegment(p1,p2,c);
			}
		}
		public function JointDestroyed(joint:b2Joint):void{
			
		}
		public function Key(code:String):void{
			
		}
		public function KeyUp(code:String):void{
			
		}
		public function KeySpecial(keyCode:uint):void{
			
		}
		public function RandomFloat(a:Number,b:Number):Number{
			var span:Number = Math.abs(a-b);
			return a + span*Math.random();
		}
	}
}
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.Joints.b2Joint;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyType;
import Box2D.Dynamics.b2DestructionListener;
import Box2D.Dynamics.b2Fixture;
import Box2D.Dynamics.b2QueryCallback;

import Framework.Test;

class QueryCallback extends b2QueryCallback
{
	public var m_point:b2Vec2
	public var m_fixture:b2Fixture;
	public function QueryCallback(point:b2Vec2)
	{
		m_point = point;
	}
	public override function ReportFixture(fixture:b2Fixture):Boolean
	{
		var body:b2Body = fixture.GetBody();
		var a:int = body.GetType();
		if(body.GetType()==b2BodyType.b2_dynamicBody){
			var inside:Boolean = fixture.TestPoint(m_point);
			if(inside){
				m_fixture = fixture;
				// We are done, terminate the query.
				return false;
			}
		}
		// Continue the query.
		return true;
	}
}

class DestructionListener extends b2DestructionListener
{
	private var test:Test
	public function DestructionListener(test:Test)
	{
		this.test = test;	
	}
	public override function SayGoodbyeFixture(fixture:b2Fixture):void{
		
	}
	public override function SayGoodbyeJoint(joint:b2Joint):void
	{
		if(joint==test.m_mouseJoint){
			test.m_mouseJoint = null;
		}		
		else{
			test.JointDestroyed(joint);
		}
	}
}